package menu

import (
	"AccessAdmin/internal/dao"
	"AccessAdmin/internal/model"
	"AccessAdmin/internal/model/entity"
	"AccessAdmin/internal/service"
	"context"
	"github.com/gogf/gf/v2/frame/g"
	"reflect"
)

type sMenu struct{}

func init() {
	service.RegisterMenu(New())
}

func New() *sMenu {
	return &sMenu{}
}

// GetList 获取菜单列表
func (s *sMenu) GetList(ctx context.Context, in model.MenuGetListInput) (out *model.MenuGetListOutput, err error) {
	out = &model.MenuGetListOutput{
		Page: in.Page,
		Size: in.Size,
	}
	m := dao.Menu.Ctx(ctx)
	if in.Title != "" {
		m = m.WhereLike(dao.Menu.Columns().Title, in.Title)
	}
	if in.Permission != "" {
		m = m.WhereLike(dao.Menu.Columns().Permission, in.Permission)
	}
	if in.Status > 0 {
		m = m.Where(dao.Menu.Columns().Status, in.Status-1)
	}
	out.Total, err = m.Count()
	if err != nil {
		return out, err
	}
	// 全量查出来
	err = m.OrderDesc(dao.Menu.Columns().Id).Scan(&out.List)
	if err != nil {
		return nil, err
	}
	if len(out.List) == 0 {
		return nil, nil
	}
	return out, nil
}

// GetDetail 获取菜单详情
func (s *sMenu) GetDetail(ctx context.Context, in model.MenuGetDetailInput) (out *model.MenuGetDetailOutput, err error) {
	out = &model.MenuGetDetailOutput{}
	err = dao.Menu.Ctx(ctx).Where(dao.Menu.Columns().Id, in.Id).Scan(&out)
	if err != nil {
		return nil, err
	}
	return out, nil
}

// Create 创建菜单
func (s *sMenu) Create(ctx context.Context, in model.MenuCreateInput) (out model.MenuCreateOutput, err error) {
	lastInsertID, err := dao.Menu.Ctx(ctx).Data(in).InsertAndGetId()
	if err != nil {
		return out, err
	}
	return model.MenuCreateOutput{MenuId: uint(lastInsertID)}, err
}

// Update 修改菜单
func (s *sMenu) Update(ctx context.Context, in model.MenuUpdateInput) error {
	_, err := dao.Menu.Ctx(ctx).Data(in).FieldsEx(dao.Menu.Columns().Id).Where(dao.Menu.Columns().Id, in.Id).Update()
	if err != nil {
		return err
	}
	return nil
}

// GetMenuByUserId 登录获取当前人菜单及权限信息
func (s *sMenu) GetMenuByUserId(ctx context.Context, UserId uint) (menu []*model.MenuItem, route []*model.MenuData, err error) {
	var menuData []*model.MenuData
	if !service.User().IsAdmin(ctx, UserId) {
		err = dao.UserRole.Ctx(ctx).As("ur").LeftJoin(dao.RoleMenu.Table(), "rm", "ur.role_id=rm.role_id").LeftJoin(dao.Menu.Table(), "m", "rm.menu_id=m.id").Where(g.Map{
			"m.is_hide":  0,
			"ur.user_id": UserId,
		}).Fields(
			"m."+dao.Menu.Columns().Id,
			"m."+dao.Menu.Columns().Title,
			"m."+dao.Menu.Columns().Pid,
			"m."+dao.Menu.Columns().Permission,
			"m."+dao.Menu.Columns().Path,
			"m."+dao.Menu.Columns().Icon,
			"m."+dao.Menu.Columns().Type).OrderDesc(dao.Menu.Columns().Sort).Scan(&menuData)
	} else {
		err = dao.Menu.Ctx(ctx).Where(dao.Menu.Columns().IsHide, 0).Fields(
			dao.Menu.Columns().Id,
			dao.Menu.Columns().Title,
			dao.Menu.Columns().Pid,
			dao.Menu.Columns().Permission,
			dao.Menu.Columns().Path,
			dao.Menu.Columns().Icon,
			dao.Menu.Columns().Type).OrderDesc(dao.Menu.Columns().Sort).Scan(&menuData)
	}
	if err != nil {
		return nil, nil, err
	}
	var menus []*model.MenuItem
	for _, item := range menuData {
		if item.Type == 0 {
			menus = append(menus, &model.MenuItem{
				MenuData: model.MenuData{
					Id:         item.Id,
					Title:      item.Title,
					Pid:        item.Pid,
					Path:       item.Path,
					Icon:       item.Icon,
					Permission: item.Permission,
					Type:       item.Type,
				},
			})
		}
	}
	return buildTree(menus, 0), menuData, nil
}

// GetMenuTree 获取菜单树
func (s *sMenu) GetMenuTree(ctx context.Context) ([]*model.MenuItem, error) {
	var menus []*model.MenuItem
	err := dao.Menu.Ctx(ctx).Fields(
		dao.Menu.Columns().Id,
		dao.Menu.Columns().Title,
		dao.Menu.Columns().Pid,
		dao.Menu.Columns().Permission,
		dao.Menu.Columns().Path,
		dao.Menu.Columns().Icon).Where(
		g.Map{
			dao.Menu.Columns().IsHide: 0,
		}).Scan(&menus)
	if err != nil {
		return nil, err
	}
	return buildTree(menus, 0), nil
}

// GetRoleMenus 授权获取角色信息
func (s *sMenu) GetRoleMenus(ctx context.Context, RoleId uint) ([]model.UserRoleAuthTreeOutput, error) {
	var roleMenu []*entity.RoleMenu
	err := dao.RoleMenu.Ctx(ctx).Where(dao.RoleMenu.Columns().RoleId, RoleId).Scan(&roleMenu)
	if err != nil {
		return nil, err
	}
	var menus []*model.MenuItem
	err = dao.Menu.Ctx(ctx).Fields(
		dao.Menu.Columns().Id,
		dao.Menu.Columns().Title,
		dao.Menu.Columns().Pid,
		dao.Menu.Columns().Permission,
		dao.Menu.Columns().Path,
		dao.Menu.Columns().Icon).Where(dao.Menu.Columns().IsHide, 0).Scan(&menus)
	if err != nil {
		return nil, err
	}
	var userRoleAuth []model.UserRoleAuthTreeOutput
	for _, item := range menus {
		userRoleAuthTreeOutput := model.UserRoleAuthTreeOutput{
			Id:   item.Id,
			Pid:  item.Pid,
			Name: item.Title,
			Open: true,
		}
		for _, val := range roleMenu {
			if uint(val.MenuId) == item.Id {
				userRoleAuthTreeOutput.Checked = true
				break
			}
		}
		userRoleAuth = append(userRoleAuth, userRoleAuthTreeOutput)
	}
	return userRoleAuth, nil
}

//生成菜单树结构
func buildTree(menus []*model.MenuItem, pid uint) []*model.MenuItem {
	//定义子节点目录
	var nodes []*model.MenuItem
	if reflect.ValueOf(menus).IsValid() {
		//循环所有一级菜单
		for _, v := range menus {
			//查询所有该菜单下的所有子菜单
			if v.Pid == pid {
				//特别注意压入元素不是单个所有加三个 **...** 告诉切片无论多少元素一并压入
				v.Children = append(v.Children, buildTree(menus, v.Id)...)
				nodes = append(nodes, v)
			}
		}
	}
	return nodes
}
